package com.itelite.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.itelite.common.info.Result;
import com.itelite.common.util.JwtTokenUtils;
import com.itelite.domain.pojo.LoginUser;
import com.itelite.domain.pojo.User;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

/**
 * @author 沈洋 邮箱:1845973183@qq.com
 **/
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private final ThreadLocal<Integer> rememberMe = new ThreadLocal<>();
    private final AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
        super.setFilterProcessesUrl("/login");
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        String username = "";
        String password = "";
        String remembermeStr = "0";
        LoginUser user = null;
        if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
            user  = (LoginUser) request.getAttribute("jsonLoginUser");
            rememberMe.set(user.getRememberMe());
        }else {
            user = new LoginUser();
            username = request.getParameter("username")==null?username:obtainUsername(request);
            password = request.getParameter("password")==null?password:obtainPassword(request);
            remembermeStr = request.getParameter("rememberMe")==null?remembermeStr:request.getParameter("rememberMe");
            user.setUsername(username);
            user.setPassword(password);
            int t = 0;
            if(!StringUtils.isEmpty(remembermeStr)){
                try {
                    t=Integer.parseInt(remembermeStr);
                } catch (NumberFormatException e) {
                    throw new RuntimeException("remember格式错误");
                }
            }
            rememberMe.set(t);
        }
        return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>())
        );
    }

    // 成功验证后调用的方法
    // 如果验证成功，就生成token并返回
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        SecurityContextHolder.getContext().setAuthentication(authResult);
        User jwtUser = (User) authResult.getPrincipal();
        logger.info(jwtUser.getRealName()+"登录成功");
        Integer remember = rememberMe.get();
        JwtTokenUtils.createJwt(jwtUser,remember,response);
    }

    // 这是验证失败时候调用的方法
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
//        super.unsuccessfulAuthentication(request,response,failed);
        //根据配置中来选择是执行跳转,还是返回字符串
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().write(new ObjectMapper().writeValueAsString(Result.failure(failed.getMessage())));
    }
}
